home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_065 / pascaltoc / proc.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  14KB  |  493 lines

  1. /*--- proc.c -------------------------------------------------------------
  2. Procedure, type, variable, and label parsing routines for the Pascal to C
  3. translator.
  4. 3/25/87 Daniel Kegel (seismo!rochester!srs!dan)
  5. --------------------------------------------------------------------------*/
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "p2c.h"
  9. #include "ktypes.h"    /* keyword type definitions */
  10.  
  11. #define SLEN 80    
  12. typedef char sstr[SLEN+1];    /* short string */
  13. #define PLEN 1024
  14. typedef char pstr[PLEN+1];    /* long string */
  15.  
  16. /* pgroup is used in parseProcedure to store the procedure's parameters */
  17. struct pgroup {
  18.     sstr pclass;    /* VAR or empty */
  19.     sstr ptype;        /* what type all these guys are */
  20.     pstr params;    /* identifiers separated by commas and space */
  21. };
  22.  
  23. boolean
  24. isSectionKeyword(k)
  25. register int k;
  26. {
  27.     return(k==T_CONST||k==T_TYPE||k==T_VAR||k==T_PROC||k==T_FUNC||k==T_BEGIN);
  28. }
  29.  
  30. /*--- skipSpace ---------------------------------------------------------
  31. Accepts and throws away space and comment tokens.
  32. ------------------------------------------------------------------------*/
  33. void
  34. skipSpace()
  35. {
  36.     do
  37.     getTok();
  38.     while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
  39.     if (cTok.kind == T_EOF) {
  40.     printf("\n/***# EOF ***/\n");
  41.     fflush(stdout);
  42.     exit(1);
  43.     }
  44. }
  45.  
  46. /*--- parseSpace ---------------------------------------------------------
  47. Accepts and prints space and comment tokens.
  48. ------------------------------------------------------------------------*/
  49. void
  50. parseSpace()
  51. {
  52.     do {
  53.     getTok();
  54.     if (cTok.kind == T_SPACE || cTok.kind == T_COMMENT)
  55.         fputs(cTok.str, stdout);
  56.     } while (cTok.kind == T_SPACE || cTok.kind == T_COMMENT);
  57.     if (cTok.kind == T_EOF) {
  58.     printf("\n/***# EOF ***/\n");
  59.     fflush(stdout);
  60.     exit(1);
  61.     }
  62. }
  63.  
  64. void
  65. expected(s)
  66. char *s;
  67. {
  68.     printf("/***# Expected %s ***/", s);
  69.     fflush(stdout);
  70. }
  71.  
  72. /*---- expectThing -------------------------------------------------------
  73. Makes sure current token is of desired type, else prints error message.
  74. ------------------------------------------------------------------------*/
  75.  
  76. void
  77. expectThing(s, k)
  78. char *s;
  79. {
  80.     if (cTok.kind != k)
  81.     expected(s);
  82. }
  83.  
  84. /*---- getThing -------------------------------------------------------
  85. Gets next nonblank token, makes sure it is desired type, else prints error 
  86. message.
  87. ------------------------------------------------------------------------*/
  88. void
  89. getThing(s, k)
  90. char *s;
  91. int k;
  92. {
  93.     skipSpace();
  94.     expectThing(s, k);
  95. }
  96.  
  97. /*---- parseVarDec ----------------------------------------------------
  98. Translates one (possibly multi-)variable declaration.
  99. Works for complex types, but can't be used to parse procedure parameters.
  100. On entry, cTok is first token in identifier list.
  101. On exit, cTok is the token after the type- probably T_SEMI.
  102. Semicolon is translated, too.
  103. ----------------------------------------------------------------------*/
  104.  
  105. struct ident {            /* Used to save variable declaration body */
  106.     char *str;            /* until type is known */
  107.     int  kind;
  108. };
  109. #define MAXIDENTS 132        /* allows about 32 variables */
  110.  
  111. void
  112. parseVarDec()
  113. {
  114.     void parseTypeDecl();        /* forward declaration */
  115.     sstr indir, index;
  116.     struct ident idents[MAXIDENTS];
  117.     int i, n;
  118.  
  119.     /* Get identifiers, up to the colon that marks end of list */
  120.     n=0;
  121.     while (cTok.kind != T_COLON) {
  122.     if (n == MAXIDENTS-1)
  123.         printf("/***# Variable declaration too long ***/");
  124.     if (n == MAXIDENTS) n--;
  125.     idents[n].str = MALLOC(char, strlen(cTok.str));
  126.     strcpy(idents[n].str, cTok.str);
  127.     idents[n++].kind = cTok.kind;
  128.     if (cTok.kind != T_ZIP && cTok.kind != T_COMMA 
  129.     && cTok.kind != T_SPACE && cTok.kind != T_COMMENT)
  130.         expected(" (variable declaration) comma or identifier");
  131.     getTok();        /* don't nuke spaces or comments */
  132.     }
  133.  
  134.     /* Output any whitespace given before the type declaration */
  135.     for (i=0; i<n&&(idents[i].kind==T_SPACE||idents[i].kind==T_COMMENT); i++){
  136.     fputs(idents[i].str, stdout);
  137.     free(idents[i].str);
  138.     }
  139.  
  140.     /* Translate type specification */
  141.     indir[0]=index[0]='\0';
  142.     parseTypeDecl(indir, index);
  143.  
  144.     /* Output the identifiers, with appropriate modification for 
  145.        ptr & array types */
  146.     putchar(' ');        /* separate RECORD from first element...? */
  147.     for (; i<n; i++) {
  148.     if (idents[i].kind == T_ZIP && indir[0]!='\0')
  149.         fputs(indir, stdout);
  150.     fputs(idents[i].str, stdout);
  151.     if (idents[i].kind == T_ZIP && index[0]!='\0')
  152.         fputs(index, stdout);
  153.     free(idents[i].str);
  154.     }
  155.     if (cTok.kind == T_SEMI)
  156.     putchar(';');
  157. }
  158.  
  159. /*---- parseProcedure -------------------------------------------------------
  160. On entry, cTok is "PROCEDURE" or "FUNCTION".
  161. On exit, cTok is the token after the semicolon after the function header.
  162.  
  163. Turns declarations like
  164.     foo(a:int; b:int)
  165. into
  166.     foo(a,b)
  167.     int a;
  168.     int b;
  169.  
  170. Breaks up function declarations into 
  171.     1. name
  172.     2. parameter declarations
  173.     3. type (or 'void', if procedure)
  174. Breaks up parameter declarations into an array of pgroups.
  175. ----------------------------------------------------------------------------*/
  176. void
  177. parseProcedure()
  178. {
  179.     boolean isProcedure;
  180.     boolean isForward;
  181.     sstr fnName;
  182.     sstr fnType;
  183.     struct pgroup *pgps=NULL;
  184.     int i, npgp=0;
  185.     register struct pgroup *p;
  186.  
  187.     /* Remember whether is returns a value or not */
  188.     isProcedure = (cTok.kind == T_PROC);
  189.     /* Get function or procedure name, skipping space & comments */
  190.     getThing("function name", T_ZIP);
  191.     strcpy(fnName, cTok.str);
  192.     skipSpace();            /* eat the function name */
  193.     /* Get open paren (or semicolon of a parameterless procedure or fn) */
  194.     if (cTok.kind == T_LPAREN) {
  195.     do {
  196.         register char *cp;
  197.         /* Allocate and initialize another parameter group */
  198.         if (npgp++ == 0) pgps=MALLOC(struct pgroup, 1);
  199.         else pgps = REALLOC(pgps, struct pgroup, npgp);
  200.         p = pgps + npgp-1;
  201.         p->pclass[0] = p->ptype[0] = '\0';
  202.  
  203.         /* Get optional class keyword */
  204.         skipSpace();        /* eat the paren or semicolon */
  205.         if (cTok.kind == T_VAR) {
  206.         strcpy(p->pclass, cTok.str);
  207.         skipSpace();        /* eat the class keyword */
  208.         }
  209.         /* Get identifier list & type */
  210.         cp = p->params;
  211.         /* Get identifiers, up to the colon that marks end of list */
  212.         while (cTok.kind != T_COLON) {
  213.         register char *cq=cTok.str;
  214.         if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
  215.             expected(" (variable declaration) comma or identifier");
  216.         while (*cp++ = *cq++)
  217.             ;
  218.         cp--;
  219.         skipSpace();
  220.         }
  221.         *cp = 0;
  222.  
  223.         /* Get type specifier, which may be many tokens.  Primitive. */
  224.         skipSpace();
  225.         p->ptype[0]=0;
  226.         do {
  227.         strcat(p->ptype, cTok.str);
  228.         skipSpace();
  229.         } while (cTok.kind != T_SEMI && cTok.kind != T_RPAREN);
  230.     } while (cTok.kind == T_SEMI);
  231.     expectThing(") at end of param list", T_RPAREN);
  232.     skipSpace();
  233.     }
  234.     /* Get return type */
  235.     if (isProcedure) {
  236.     strcpy(fnType, "void");
  237.     } else {
  238.     expectThing(":", T_COLON);
  239.     getThing("function type", T_ZIP);
  240.     strcpy(fnType, cTok.str);
  241.     skipSpace();
  242.     }
  243.     expectThing("semicolon", T_SEMI);
  244.     /* Get optional FORWARD keyword */
  245.     skipSpace();
  246.     if (isForward = (cTok.kind == T_FORWARD)) {
  247.     getThing(";", T_SEMI);
  248.     skipSpace();
  249.     }
  250.  
  251.     /* Output the first part of the translated function declaration */
  252.     printf("%s %s(", fnType, fnName);
  253.     for (i=0, p=pgps; i++ < npgp; p++) {
  254.     fputs(p->params, stdout);
  255.     if (i<npgp) putchar(',');
  256.     }
  257.     putchar(')');
  258.     if (isForward)
  259.     puts(";");
  260.     else {
  261.     /* Output second part */
  262.     putchar('\n');
  263.     for (i=0, p=pgps; i++ < npgp; p++) {
  264.         if (p->pclass[0])
  265.         fputs(p->pclass, stdout);    /* already xlated */
  266.         printf("%s %s;\n", p->ptype, p->params);
  267.     }
  268.     }
  269. }
  270.  
  271. /*--- convertArrayBound -----------------------------------------------------
  272. Given the upper bound of a Pascal array, append the C array size specification
  273. to the buffer tindex.
  274. Lower bounds are ignored, 'cause it's safe to do so, and impossibly difficult
  275. to handle.
  276. ----------------------------------------------------------------------------*/
  277. void
  278. convertArrayBound(s, tindex)
  279. char *s, *tindex;
  280. {
  281.     sstr buf;
  282.     int ubound;
  283.  
  284.     ubound = atoi(s);
  285.     if (ubound == 0) {
  286.     /* Probably symbolic */
  287.     sprintf(buf, "[%s+1]", s);
  288.     } else {
  289.     if (ubound < 0)
  290.         expected("positive upper bound");
  291.     sprintf(buf, "[%d]", ubound+1);
  292.     }
  293.     strcat(tindex, buf);
  294. }
  295.  
  296. /*---- parseTypeDecl -------------------------------------------------------
  297. Translates a type definition in place.  Appends indirection & array subscrips,
  298. if any, to the buffers tindir and tindex.
  299. Never translates the semicolon- that is done in parseType.
  300.  
  301. On entry, cTok is the token that made us expect to find a type
  302. (e.g. the colon in a variable declaration, or the equals in a type declaration,
  303. On exit, cTok is the token after the type, usually T_SEMI (but may be T_END 
  304. in the last declaration in a RECORD).
  305.  
  306. Pascal (or at least, Turbo Pascal) doesn't allow constructions like
  307.     a = ^array [0..10] of integer;
  308. rather, it forces you to define the base type, too:
  309.     b = array [0..10] of integer;
  310.     a = ^b;
  311. Thus any type definition can be unambiguously broken up into 2 parts:
  312.     - the base type (which may be complex)
  313.     - if pointer, how many levels of indirection
  314.       else if array, how many indices the type has, with limits
  315. -----------------------------------------------------------------------*/
  316. void
  317. parseTypeDecl(tindir, tindex)
  318. char *tindir, *tindex;        /* buffer to put * or [n] in */
  319. {
  320.     skipSpace();        /* get initial token of type */
  321.  
  322.     switch (cTok.kind) {
  323.     case T_DEREF:        /* pointer type */
  324.     strcat(tindir, "*");
  325.     parseTypeDecl(tindir, tindex);
  326.     break;
  327.     case T_LPAREN:        /* enumerated type */
  328.     fputs("enum {", stdout);
  329.     do {
  330.         parseSpace();
  331.         if (cTok.kind != T_RPAREN)
  332.         fputs(cTok.str, stdout);
  333.     } while (cTok.kind != T_RPAREN);
  334.     getThing(";", T_SEMI);
  335.     putchar('}');
  336.     break;
  337.     case T_ARRAY:        /* array type */
  338.     getThing("[", T_LBRACKET);
  339.     do {                    /* Get all the dimensions */
  340.         getThing("lower bound", T_ZIP);    /* Ignore lower bound except */
  341.         if (cTok.str[0] == '-')        /* to make sure >= 0 */
  342.         expected("non-negative lower bound");
  343.         getThing("..", T_RANGE);
  344.         getThing("upper bound", T_ZIP);
  345.         convertArrayBound(cTok.str, tindex);
  346.         skipSpace();
  347.     } while (cTok.kind == T_COMMA);
  348.     expectThing("]", T_RBRACKET);
  349.     getThing("OF", T_OF);
  350.     parseTypeDecl(tindir, tindex);
  351.     break;
  352.     case T_STRINGTYPE:        /* Turbo (& UCSD?) string type */
  353.     printf("char");
  354.     skipSpace();
  355.     if (cTok.kind != T_LPAREN && cTok.kind != T_LBRACKET) 
  356.         expected("[ or ( after STRING");
  357.     getThing("string length", T_ZIP);
  358.     convertArrayBound(cTok.str, tindex);
  359.     skipSpace();
  360.     if (cTok.kind != T_RPAREN && cTok.kind != T_RBRACKET) 
  361.         expected("] or ) after STRING[");
  362.     getThing(";", T_SEMI);
  363.     break;
  364.     case T_FILE:        /* file type - not supported in C */
  365.     strcat(tindir, "*");
  366.     printf("FILE /* OF ");    /* show what it's a file of in the comment */
  367.     do {
  368.         skipSpace();
  369.         if (cTok.kind != T_COMMENT);    /* avoid nesting comments */
  370.         fputs(cTok.str, stdout);
  371.     } while (cTok.kind != T_SEMI);
  372.     printf(" */ ");
  373.     break;
  374.     case T_RECORD:        /* struct definition */
  375.     printf("struct {");
  376.     parseSpace();        /* eat RECORD */
  377.     do {
  378.         if (cTok.kind == T_CASE) {
  379.         printf("/***# Sorry- variant records not supported\n\t");
  380.         do {
  381.             if (cTok.kind != T_COMMENT)
  382.             fputs(cTok.str, stdout);
  383.             getTok();
  384.         } while (cTok.kind != T_END);
  385.         printf(" ***/");
  386.         break;
  387.         }
  388.         parseVarDec();
  389.         if (cTok.kind == T_SEMI)
  390.         parseSpace();
  391.         else if (cTok.kind == T_END)
  392.         putchar(';');        /* Pascal doesn't need ; but C does*/
  393.         else if (cTok.kind != T_CASE)
  394.         expected("Either semicolon or END");
  395.     } while (cTok.kind != T_END);
  396.     parseSpace();        /* eat the END, get the semi */
  397.     printf("}");
  398.     break;
  399.     case T_ZIP:            /* probably a type keyword like 'integer' */
  400.     fputs(cTok.str, stdout);
  401.     skipSpace();        /* eat the type, get the semi */
  402.     break;
  403.     default:            /* unexpected */
  404.     expected("type");
  405.     }
  406. }
  407.  
  408. /*---- parseVar -------------------------------------------------------
  409. Translates the VAR section of a program or procedure.
  410.  
  411. On entry, cTok is "VAR".
  412. On exit, cTok is any section-starting keyword.
  413. Turns declarations like
  414.     foo : ^integer;
  415. into
  416.     int *foo;
  417. ----------------------------------------------------------------------------*/
  418. void
  419. parseVar()
  420. {
  421.     getTok();        /* eat the VAR */
  422.     do {
  423.     parseVarDec();
  424.     if (cTok.kind == T_SEMI)
  425.         parseSpace();
  426.     } while (!isSectionKeyword(cTok.kind));
  427. }
  428.  
  429. /*---- parseType -----------------------------------------------------------
  430. Translates the TYPE section of a program or procedure.
  431. On entry, cTok is TYPE.
  432. On exit, cTok is any section-starting keyword.
  433.  
  434. Turns declarations like
  435.     foo = array [0..10, LO..HI] of integer;
  436.     boo = record
  437.         x : foo;
  438.         y : ^foo
  439.       end;
  440.  
  441. into
  442.     typedef integer foo[11][HI+1];
  443.     typedef struct {
  444.     foo x;
  445.     foo *y;
  446.     } boo;
  447. ---------------------------------------------------------------------------*/
  448. void
  449. parseType()
  450. {
  451.     parseSpace();
  452.     do {
  453.     sstr typ;
  454.     sstr tindir, tindex;
  455.     expectThing("type identifier", T_ZIP);
  456.     strcpy(typ, cTok.str);
  457.     parseSpace();
  458.     expectThing("=", T_EQUALS);
  459.     printf("typedef ");
  460.     tindir[0]=tindex[0]=0;
  461.     parseTypeDecl(tindir, tindex);
  462.     expectThing(";", T_SEMI);
  463.     printf(" %s%s%s;", tindir, typ, tindex);
  464.     parseSpace();
  465.     } while (!isSectionKeyword(cTok.kind));
  466. }
  467.  
  468. /*---- parseLabel -------------------------------------------------------
  469. On entry, cTok is "LABEL".
  470. On exit, cTok is whatever follows the semicolon.
  471.  
  472. Turns declarations like
  473. LABEL foo, goo;
  474. into
  475. / * LABEL foo, goo; * /
  476. ----------------------------------------------------------------------------*/
  477. void
  478. parseLabel()
  479. {
  480.     skipSpace();        /* eat the LABEL */
  481.     printf("/* LABEL ");
  482.     /* Get identifiers, up to the semicolon that marks end of list */
  483.     while (cTok.kind != T_SEMI) {
  484.     if (cTok.kind != T_ZIP && cTok.kind != T_COMMA)
  485.         expected(" (label declaration) comma or identifier");
  486.     fputs(cTok.str, stdout);
  487.     skipSpace();
  488.     }
  489.     /* Get semicolon without wiping out trailing space */
  490.     getTok();
  491.     fputs("; */", stdout);
  492. }
  493.